#include "game\Map.h"
#include <queue>

Map::Map(int width, int height)
{
	m_width = width;
	m_height = height;
	m_grid = new Tile[width * height];
	for(int i=0;i<width*height;i++) m_grid[i] = SOLID;
}

Map::~Map()
{
	if(m_grid != 0)
	{
		delete[] m_grid;
		m_grid = 0;
	}
}

bool Map::inBounds(Vec p)
{
	return !(p.x < 0 || p.x >= m_width || p.y < 0 || p.y >=m_height);
}

TileType Map::getTileType(Vec p)
{
  if(!inBounds(p)) return INVALID;
  return m_grid[p.x + p.y * m_width].getType();
}

Tile* Map::getTile(Vec p)
{
  if(!inBounds(p)) return NULL;
  return &m_grid[p.x + p.y * m_width];
}

void Map::setTileType(Vec pos, TileType t)
{
  if(!inBounds(pos)) return;
  m_grid[pos.x + pos.y * m_width] = t;
  if(t == STAIRS_DOWN) m_stairsDown = pos;  //TODO: only 1 entrance and exit per level?
  if(t == STAIRS_UP) m_stairsUp = pos;
}

bool Map::isPassable(Vec p)
{
  if(!inBounds(p)) return false;
  TileType t = m_grid[p.x + p.y * m_width].getType();
  if(t == SOLID || t == WALL || t == INVALID) return false;
  return true;
}

Path Map::path(Vec a, Vec b)
{
  Path p;
  std::vector<Vec> pre;
  pre.resize(m_width * m_height, Vec(-1,-1));  
  std::queue<Vec> q;
  q.push(a);
  pre[a.x + a.y * m_width] = Vec(-2,-2);
  while(!q.empty())
  {
    Vec v = q.front();
    q.pop();
    if(v == b) break;        
    Vec dir[8] = {Vec(-1,-1), Vec(0,-1), Vec(1,-1), Vec(-1,0), Vec(1,0), Vec(-1,1), Vec(0,1), Vec(1,1)};
    for(int i=0;i<8;i++)
    {
      Vec vNew = v + dir[i];
      if(inBounds(vNew) && pre[vNew.x + vNew.y * m_width] == Vec(-1,-1) && isPassable(vNew))
      {
        q.push(vNew); pre[vNew.x + vNew.y * m_width] = v;
      }
    }
  }
  
  if(pre[b.x + b.y * m_width] == Vec(-1,-1)) return p;
  
  Vec r = b;
  while(r != Vec(-2,-2))
  {
    p.push_back(r);
    r = pre[r.x + r.y * m_width];
  }
  std::reverse(p.begin(), p.end());

  return p;
}